package com.tes;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.anddev.andengine.audio.sound.Sound;
import org.anddev.andengine.audio.sound.SoundFactory;
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.ZoomCamera;
import org.anddev.andengine.engine.camera.hud.HUD;
import org.anddev.andengine.engine.camera.hud.controls.BaseOnScreenControl;
import org.anddev.andengine.engine.camera.hud.controls.BaseOnScreenControl.IOnScreenControlListener;
import org.anddev.andengine.engine.camera.hud.controls.DigitalOnScreenControl;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.engine.handler.physics.PhysicsHandler;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXObject;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXObjectGroup;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
import org.anddev.andengine.entity.layer.tiled.tmx.util.exception.TMXLoadException;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.background.ColorBackground;
import org.anddev.andengine.entity.scene.menu.MenuScene;
import org.anddev.andengine.entity.scene.menu.MenuScene.IOnMenuItemClickListener;
import org.anddev.andengine.entity.scene.menu.item.IMenuItem;
import org.anddev.andengine.entity.scene.menu.item.TextMenuItem;
import org.anddev.andengine.entity.scene.menu.item.decorator.ColorMenuItemDecorator;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.entity.text.ChangeableText;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.font.FontFactory;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.Debug;
import org.anddev.andengine.util.HorizontalAlign;

public class TesGame2 extends BaseGameActivity implements
		IOnMenuItemClickListener {

	// ukuran layar
	static final int CAMERA_WIDTH = 480;
	static final int CAMERA_HEIGHT = 320;

	// camera
	private ZoomCamera mCamera;

	// scene
	private Scene mainScene;
	private Scene loadScene;

	// menu scene
	private MenuScene menuScene;

	static final int MENU_START = 100;
	static final int MENU_EXIT = 0;

	// tiled map
	private TMXTiledMap mTMXTiledMap;

	// score
	private BitmapTextureAtlas tHighScore;
	private Font mHighScore;

	// player
	private BitmapTextureAtlas tPlayer;
	private TiledTextureRegion mPlayer;

	// control
	private DigitalOnScreenControl playerControl;

	private BitmapTextureAtlas tControlBase;
	private TextureRegion mControlBase;

	private BitmapTextureAtlas tControlKnob;
	private TextureRegion mControlKnob;

	// duration
	private long[] duration = { 100, 100, 100 };

	// direction
	private enum PlayerDirection {
		NONE, UP, DOWN, LEFT, RIGHT
	}

	private PlayerDirection playerDirection = PlayerDirection.NONE;

	// player speed
	private float playerVelocty = 25;

	// timer
	private TimerHandler timerHandler;
	private int time = 10;
	
	// sound
	private Sound sTick;

	@Override
	public Engine onLoadEngine() {
		this.mCamera = GameResource.zoomCamera;

		Engine engine = new Engine(new EngineOptions(true,
				ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(
						CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera)
				.setNeedsSound(true).setNeedsMusic(true));

		return engine;
	}

	@Override
	public void onLoadResources() {
		// set path
		FontFactory.setAssetBasePath("font/");
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
		SoundFactory.setAssetBasePath("sound/");

		// sound
		try {
			sTick = SoundFactory.createSoundFromAsset(
					mEngine.getSoundManager(), this, "tick.wav");
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// high score
		tHighScore = GameResource.tFontQuartz;
		mHighScore = GameResource.mFontQuartz;

		// player
		tPlayer = GameResource.tPlayer;
		mPlayer = GameResource.mPlayer;

		// control
		tControlBase = GameResource.tControlBase;
		mControlBase = GameResource.mControlBase;

		tControlKnob = GameResource.tControlKnob;
		mControlKnob = GameResource.mControlKnob;

		// load resource
		mEngine.getTextureManager().loadTextures(tHighScore, tPlayer,
				tControlBase, tControlKnob);
		mEngine.getFontManager().loadFont(mHighScore);
	}

	@Override
	public Scene onLoadScene() {
		this.mEngine.registerUpdateHandler(new FPSLogger());

		loadScene = new Scene();
		loadScene.setBackground(new ColorBackground(1.0f, 0.0f, 1.0f));
		menuScene = createMenuFinish();

		return loadScene;
	}

	@Override
	public void onLoadComplete() {
		this.mEngine.getScene().setChildScene(menuScene);
	}

	@Override
	public boolean onMenuItemClicked(MenuScene pMenuScene, IMenuItem pMenuItem,
			float pMenuItemLocalX, float pMenuItemLocalY) {

		switch (pMenuItem.getID()) {
		case MENU_START:
			mEngine.getScene().clearChildScene();
//			remain = time;
//			timerHandler.reset();
			mainScene = createMainScene();
			mEngine.setScene(mainScene);
			break;

		default:
			break;
		}

		return false;
	}

	protected MenuScene createMenuFinish() {
		MenuScene mScene = new MenuScene(this.mCamera);

		IMenuItem startMenuItem = new ColorMenuItemDecorator(new TextMenuItem(
				MENU_START, this.mHighScore, "START"), 1.0f, 0.0f, 0.0f, 0.0f,
				0.0f, 1.0f);
		mScene.addMenuItem(startMenuItem);

		mScene.setBackgroundEnabled(false);
		mScene.setOnMenuItemClickListener(this);

		return mScene;
	}

	protected Scene createMainScene() {
		final Scene scene = new Scene();

		final HUD hud = new HUD();
		final List<Rectangle> listUnpassObject = new ArrayList<Rectangle>();
		final List<Rectangle> listGoolObject = new ArrayList<Rectangle>();
		final Rectangle start = new Rectangle(0, 0, 0, 0);

		// load the tmx file
		try {
			final TMXLoader tmxLoader = new TMXLoader(this,
					this.mEngine.getTextureManager(), TextureOptions.NEAREST);
			this.mTMXTiledMap = tmxLoader.loadFromAsset(this, "level01.tmx");
		} catch (final TMXLoadException tmxle) {
			Debug.e(tmxle);
		}

		// set camera bound
		final float tmxWidht = mTMXTiledMap.getTileColumns()
				* mTMXTiledMap.getTileWidth();
		final float tmxHeight = mTMXTiledMap.getTileRows()
				* mTMXTiledMap.getTileHeight();

		this.mCamera.setBounds(0, tmxWidht, 0, tmxHeight);
		this.mCamera.setBoundsEnabled(true);

		// add the terain to scene
		for (TMXLayer layer : mTMXTiledMap.getTMXLayers()) {
			if (layer.getTMXLayerProperties().containsTMXProperty("terrain",
					"true")) {
				scene.attachChild(layer);
			}
		}

		// add object that can collide with player
		for (TMXObjectGroup objectGroup : this.mTMXTiledMap
				.getTMXObjectGroups()) {

			if (objectGroup.getTMXObjectGroupProperties().containsTMXProperty(
					"collide", "true")) {
				for (TMXObject tmxObject : objectGroup.getTMXObjects()) {
					Rectangle rectangle = new Rectangle(tmxObject.getX(),
							tmxObject.getY(), tmxObject.getWidth(),
							tmxObject.getHeight());
					listUnpassObject.add(rectangle);
				}
			}

			if (objectGroup.getTMXObjectGroupProperties().containsTMXProperty(
					"gool", "true")) {
				for (TMXObject tmxObject : objectGroup.getTMXObjects()) {
					Rectangle rectangle = new Rectangle(tmxObject.getX(),
							tmxObject.getY(), tmxObject.getWidth(),
							tmxObject.getHeight());
					listGoolObject.add(rectangle);
				}
			}

			if (objectGroup.getTMXObjectGroupProperties().containsTMXProperty(
					"start", "true")) {
				for (TMXObject tmxObject : objectGroup.getTMXObjects()) {
					start.setPosition(tmxObject.getX(), tmxObject.getY());
				}
			}
		}

		// player
		final AnimatedSprite sPlayer = new AnimatedSprite(start.getX(),
				start.getY(), mPlayer);
		final PhysicsHandler physicsPlayer = new PhysicsHandler(sPlayer);
		physicsPlayer.setVelocity(0, 0);
		sPlayer.registerUpdateHandler(physicsPlayer);
		sPlayer.registerUpdateHandler(new IUpdateHandler() {

			@Override
			public void reset() {

			}

			@Override
			public void onUpdate(float pSecondsElapsed) {
				// check collision for wall
				for (Rectangle rectangle : listUnpassObject) {
					if (sPlayer.collidesWith(rectangle)) {
						physicsPlayer.setVelocity(
								-physicsPlayer.getVelocityX() * 2,
								-physicsPlayer.getVelocityY() * 2);
					}
				}

				for (Rectangle rectangle : listGoolObject) {
					if (sPlayer.collidesWith(rectangle)) {
						sPlayer.setInitialPosition();
					}
				}

				// check if player out of field
				// up
				if (sPlayer.getY() < 0 && playerDirection == PlayerDirection.UP) {
					physicsPlayer.setVelocityY(-physicsPlayer.getVelocityY());
				}

				// left
				if (sPlayer.getX() < 0
						&& playerDirection == PlayerDirection.LEFT) {
					physicsPlayer.setVelocityX(-physicsPlayer.getVelocityX());
				}

				// down
				if (sPlayer.getY() > (tmxHeight - sPlayer.getHeight())
						&& playerDirection == PlayerDirection.DOWN) {
					physicsPlayer.setVelocityY(-physicsPlayer.getVelocityY());
				}

				// right
				if (sPlayer.getX() > (tmxWidht - sPlayer.getWidth())
						&& playerDirection == PlayerDirection.RIGHT) {
					physicsPlayer.setVelocityX(-physicsPlayer.getVelocityX());
				}
			}
		});

		scene.attachChild(sPlayer);
		mCamera.setChaseEntity(sPlayer);

		// object
		for (TMXLayer layer : mTMXTiledMap.getTMXLayers()) {
			if (layer.getTMXLayerProperties().containsTMXProperty("object",
					"true")) {
				scene.attachChild(layer);
			}
		}

		// high score
		final ChangeableText cText = new ChangeableText(CAMERA_WIDTH - 70, 10,
				mHighScore, "XXXX", HorizontalAlign.RIGHT, "XXXX".length());
		hud.attachChild(cText);

		// control
		this.playerControl = new DigitalOnScreenControl(
				0 + (this.mControlKnob.getHeight() / 2),
				CAMERA_HEIGHT
						- (this.mControlBase.getHeight() + this.mControlKnob
								.getHeight() / 2), this.mCamera,
				this.mControlBase, this.mControlKnob, 0.1f,
				new IOnScreenControlListener() {

					@Override
					public void onControlChange(
							BaseOnScreenControl pBaseOnScreenControl,
							float pValueX, float pValueY) {

						if (pValueY == 1) {
							// Up
							if (playerDirection != PlayerDirection.DOWN) {
								sPlayer.animate(duration, 0, 2, true);
								playerDirection = PlayerDirection.DOWN;
							}
						} else if (pValueY == -1) {
							// Down
							if (playerDirection != PlayerDirection.UP) {
								sPlayer.animate(duration, 9, 11, true);
								playerDirection = PlayerDirection.UP;
							}
						} else if (pValueX == -1) {
							// Left
							if (playerDirection != PlayerDirection.LEFT) {
								sPlayer.animate(duration, 3, 5, true);
								playerDirection = PlayerDirection.LEFT;
							}
						} else if (pValueX == 1) {
							// Right
							if (playerDirection != PlayerDirection.RIGHT) {
								sPlayer.animate(duration, 6, 8, true);
								playerDirection = PlayerDirection.RIGHT;
							}
						} else {
							if (sPlayer.isAnimationRunning()) {
								sPlayer.stopAnimation();
								playerDirection = PlayerDirection.NONE;
							}
						}

						physicsPlayer.setVelocity(pValueX * playerVelocty,
								pValueY * playerVelocty);
					}
				});

		playerControl.getControlBase().setAlpha(0.075f);
		playerControl.getControlKnob().setAlpha(0.75f);
		playerControl.refreshControlKnobPosition();

		this.getEngine().getCamera().setHUD(hud);

		scene.setChildScene(this.playerControl);
		scene.setTouchAreaBindingEnabled(true);

		// timer handler
		timerHandler = new TimerHandler(1.0f, new ITimerCallback() {
			int remainTime = time;
			
			@Override
			public void onTimePassed(TimerHandler pTimerHandler) {
				String text = remainTime + "";
				for (int i = 0; i < 4 - text.length(); i++) {
					text = "0" + text;
				}

				cText.setText(text);

				if (remainTime < 20) {
					sTick.play();
				}

				if (remainTime <= 0) {
					menuScene = createMenuFinish();
					scene.setChildScene(menuScene, false, true, true);
				}

				if (remainTime > 0) {
					remainTime--;
					pTimerHandler.reset();
				}
			}
		});

		scene.registerUpdateHandler(timerHandler);

		return scene;
	}
}
